/******************************************************************************
 * Copyright (C) 2015  671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#include "Ucop/Storage/SQLStorage.h"
using namespace Ucop::DBC;


namespace Ucop {
namespace Storage {

	SQLStorageBase::SQLStorageBase()
		: _MytableName(NULL)
		, _MyentryField(NULL)
		, _MysrcFormat(NULL)
		, _MydstFormat(NULL)

		, _MydstFieldCount(0)
		, _MysrcFieldCount(0)
		, _MyrecordCount(0)
		, _MymaxEntry(0)
		, _MyrecordSize(0)

		, _Mydata(NULL)
	{
	}

	void SQLStorageBase::Initialize(const char* tableName, const char* entry_field, const char* src_format, const char* dst_format)
	{
		_MytableName = tableName;
		_MyentryField = entry_field;
		_MysrcFormat = src_format;
		_MydstFormat = dst_format;

		_MysrcFieldCount = strlen(_MysrcFormat);
		_MydstFieldCount = strlen(_MydstFormat);
	}

	char* SQLStorageBase::CreateRecord(std::uint32_t recordId)
	{
		char* newRecord = &_Mydata[_MyrecordCount * _MyrecordSize];
		++_MyrecordCount;

		JustCreatedRecord(recordId, newRecord);
		return newRecord;
	}

	void SQLStorageBase::PrepareToLoad(std::uint32_t maxEntry, std::uint32_t recordCount, std::uint32_t recordSize)
	{
		_MymaxEntry = maxEntry;
		_MyrecordSize = recordSize;

		delete[] _Mydata;
		_Mydata = new char[recordCount * _MyrecordSize];
		memset(_Mydata, 0, recordCount * _MyrecordSize);

		_MyrecordCount = 0;
	}

	void SQLStorageBase::Free()
	{
		if (!_Mydata)
		{
			return;
		}

		std::uint32_t offset = 0;
		for (std::uint32_t x = 0; x < _MydstFieldCount; ++x)
		{
			switch (_MydstFormat[x])
			{
			case DBC_FF_LOGIC:
				offset += sizeof(bool);
				break;
			case DBC_FF_STRING:
			{
				for (std::uint32_t recordItr = 0; recordItr < _MyrecordCount; ++recordItr)
				{
					delete[] * (char**)((char*)(_Mydata + (recordItr * _MyrecordSize)) + offset);
				}

				offset += sizeof(char*);
				break;
			}
			case DBC_FF_NA:
			case DBC_FF_INT:
				offset += sizeof(std::uint32_t);
				break;
			case DBC_FF_BYTE:
			case DBC_FF_NA_BYTE:
				offset += sizeof(char);
				break;
			case DBC_FF_FLOAT:
			case DBC_FF_NA_FLOAT:
				offset += sizeof(float);
				break;
			case DBC_FF_NA_POINTER:
				// TODO- possible (and small) memleak here possible
				offset += sizeof(char*);
				break;
			case DBC_FF_IND:
			case DBC_FF_SORT:
				assert(false && "SQL storage not have sort field types");
				break;
			default:
				assert(false && "unknown format character");
				break;
			}
		}
		delete[] _Mydata;
		_Mydata = NULL;
		_MyrecordCount = 0;
	}



	void SQLStorage::EraseEntry(std::uint32_t id)
	{
		_Myindex[id] = NULL;
	}

	void SQLStorage::Free()
	{
		SQLStorageBase::Free();
		delete[] _Myindex;
		_Myindex = NULL;
	}

	SQLStorage::SQLStorage(const char* fmt, const char* _entry_field, const char* sqlname)
	{
		Initialize(sqlname, _entry_field, fmt, fmt);
		_Myindex = NULL;
	}

	SQLStorage::SQLStorage(const char* src_fmt, const char* dst_fmt, const char* _entry_field, const char* sqlname)
	{
		Initialize(sqlname, _entry_field, src_fmt, dst_fmt);
		_Myindex = NULL;
	}

	void SQLStorage::PrepareToLoad(std::uint32_t maxRecordId, std::uint32_t recordCount, std::uint32_t recordSize)
	{
		// Clear (possible) old data and old index array
		Free();

		// Set index array
		_Myindex = new char*[maxRecordId];
		memset(_Myindex, 0, maxRecordId * sizeof(char*));

		SQLStorageBase::PrepareToLoad(maxRecordId, recordCount, recordSize);
	}

	void SQLHashStorage::Free()
	{
		SQLStorageBase::Free();
		_MyindexMap.clear();
	}

	void SQLHashStorage::PrepareToLoad(std::uint32_t maxRecordId, std::uint32_t recordCount, std::uint32_t recordSize)
	{
		// Clear (possible) old data and old index array
		Free();

		SQLStorageBase::PrepareToLoad(maxRecordId, recordCount, recordSize);
	}

	void SQLHashStorage::EraseEntry(std::uint32_t id)
	{
		// do not erase from m_records
		RecordMap::iterator find = _MyindexMap.find(id);
		if (find != _MyindexMap.end())
		{
			find->second = NULL;
		}
	}

	SQLHashStorage::SQLHashStorage(const char* fmt, const char* _entry_field, const char* sqlname)
	{
		Initialize(sqlname, _entry_field, fmt, fmt);
	}

	SQLHashStorage::SQLHashStorage(const char* src_fmt, const char* dst_fmt, const char* _entry_field, const char* sqlname)
	{
		Initialize(sqlname, _entry_field, src_fmt, dst_fmt);
	}

	void SQLMultiStorage::Free()
	{
		SQLStorageBase::Free();
		_MyindexMultiMap.clear();
	}

	void SQLMultiStorage::PrepareToLoad(std::uint32_t maxRecordId, std::uint32_t recordCount, std::uint32_t recordSize)
	{
		// Clear (possible) old data and old index array
		Free();

		SQLStorageBase::PrepareToLoad(maxRecordId, recordCount, recordSize);
	}

	void SQLMultiStorage::EraseEntry(std::uint32_t id)
	{
		_MyindexMultiMap.erase(id);
	}

	SQLMultiStorage::SQLMultiStorage(const char* fmt, const char* _entry_field, const char* sqlname)
	{
		Initialize(sqlname, _entry_field, fmt, fmt);
	}

	SQLMultiStorage::SQLMultiStorage(const char* src_fmt, const char* dst_fmt, const char* _entry_field, const char* sqlname)
	{
		Initialize(sqlname, _entry_field, src_fmt, dst_fmt);
	}

}}